package com.hyou.codemaker.bean.info.impl;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.mybatis.spring.SqlSessionTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.hyou.codemaker.bean.info.DbInfoOper;
import com.hyou.codemaker.bean.objdef.FieldCfg;
import com.hyou.codemaker.common.consts.ConstDataType;
import com.hyou.codemaker.config.ConfigBaseProp;
import com.hyou.codemaker.config.ConfigBeanProp;
import com.hyou.codemaker.db.dao.ColumnDao;
import com.hyou.codemaker.db.pojo.ParamColumnsBean;
import com.hyou.codemaker.db.pojo.ResultColumnsBean;
import com.hyou.codemaker.util.RegUtil;

/**
 * 从MySQL中获取数据库表信息
 * 
 * @author Changshuo.Feng
 * @version 1.0.0 2014-08-02 12:37:22
 * @version 1.3.1 2017-10-31 10:40:18 添加对Double数据类型的支持
 * @version 1.3.4 2018-03-13 16:11:37 新增getTableComment方法
 */
@Component("mySQLDbInfoOper")
public class DbMySQLInfoOperImpl implements DbInfoOper {
    
    private static final Logger log = LoggerFactory.getLogger(DbMySQLInfoOperImpl.class);
    
    @Resource(name = "configBaseProp")
    private ConfigBaseProp configBaseProp;
    
    @Resource(name = "configBeanProp")
    private ConfigBeanProp configBeanProp;
    
    @Resource(name = "sqlSessionTemplate")
    private SqlSessionTemplate sqlSessionTemplate;
    
    @Override
    public String getTableComment() {
        ColumnDao columnDao = sqlSessionTemplate.getMapper(ColumnDao.class);
        
        String schema = configBaseProp.getSchameName();
        String table = configBeanProp.getTableName();
        
        ParamColumnsBean paramBean = new ParamColumnsBean();
        paramBean.setTableSchema(schema);
        paramBean.setTableName(table);
        
        log.debug("ParamColumnsBean=[{}]", paramBean);
        
        return columnDao.selectTableComment(paramBean);
    }
    
    /**
     * 通过数据库查询的方式获取指定表的配置
     */
    @Override
    public List<FieldCfg> getFieldCfgList() {
        
        List<ResultColumnsBean> rsLst = getTableColumnInfos();
        if (CollectionUtils.isEmpty(rsLst)) {
            log.info("getTableColumnInfos 查询结果为空");
            return new ArrayList<>();
        }
        
        List<FieldCfg> fieldCfgLst = new ArrayList<>();
        
        String columnName;
        String fieldName;
        String columnType;
        String dataType;
        String javaType;
        FieldCfg fieldCfg;
        
        for (ResultColumnsBean resultColumnBean : rsLst) {
            log.debug("resultColumnBean=[{}]", resultColumnBean);
            
            fieldCfg = new FieldCfg();
            
            columnName = resultColumnBean.getColumnName();
            fieldCfg.setColumnName(columnName);
            
            fieldName = RegUtil.columnToFieldName(columnName);
            fieldCfg.setName(fieldName);
            
            columnType = resultColumnBean.getColumnType();
            dataType = resultColumnBean.getDataType();
            javaType = transToJavaDataBase(dataType, columnType);
            fieldCfg.setJavaType(javaType);
            
            dataType = transToMybatisDataType(dataType);
            fieldCfg.setDatabaseType(dataType);
            
            fieldCfg.setComment(resultColumnBean.getColumnComment());
            
            fieldCfg.setNullable(resultColumnBean.getNullable());
            
            if (null != resultColumnBean.getCharacterMaximumLength()) {
                fieldCfg.setCharacterMaximumLength(String.valueOf(resultColumnBean.getCharacterMaximumLength()));
            }
            
            if (null != resultColumnBean.getNumberPrecision()) {
                fieldCfg.setNumberPrecision(String.valueOf(resultColumnBean.getNumberPrecision()));
            }
            
            if (null != resultColumnBean.getNumberScale()) {
                fieldCfg.setNumberScale(String.valueOf(resultColumnBean.getNumberScale()));
            }
            
            fieldCfgLst.add(fieldCfg);
        }
        
        return fieldCfgLst;
    }
    
    /**
     * @return 从数据库查询指定表的表结构，每个字段的基本信息封装到ResultColumnsBean中
     */
    private List<ResultColumnsBean> getTableColumnInfos() {
        ColumnDao columnDao = sqlSessionTemplate.getMapper(ColumnDao.class);
        
        String schema = configBaseProp.getSchameName();
        String table = configBeanProp.getTableName();
        
        ParamColumnsBean paramBean = new ParamColumnsBean();
        paramBean.setTableSchema(schema);
        paramBean.setTableName(table);
        
        log.debug("ParamColumnsBean=[{}]", paramBean);
        
        return columnDao.selectTableInfo(paramBean);
    }
    
    private String transToMybatisDataType(String dataType) {
        
        if (ConstDataType.MYSQL_INT.equalsIgnoreCase(dataType)) {
            return ConstDataType.MYBATIS_JDBC_INT;
        }
        
        if (ConstDataType.MYSQL_DATETIME.equalsIgnoreCase(dataType)) {
            return ConstDataType.MYBATIS_JDBC_TIMESTAMP;
        }
        
        return dataType.toUpperCase();
    }
    
    /**
     * <pre>
     * 将数据库表的列类型转换成Java数据类型
     * 
     * 版本修改历史记录：
     * 1) 1.0.0 2017-10-31 10:43:48 FengChangshuo 添加对Double数据类型的支持
     * </pre>
     * 
     * @param dataType 形如:decimal,只定义了列的类型
     * @param columnType 形如：decimal(18,0) 除了带有类型，还包含列的长度等信息
     * @return Java中对应的数据类型
     */
    private String transToJavaDataBase(String dataType, String columnType) {
        
        if (ConstDataType.MYSQL_VARCHAR.equalsIgnoreCase(dataType)) {
            // varchar -> String
            return ConstDataType.JAVA_STRING;
        }
        
        if (ConstDataType.MYSQL_CHAR.equalsIgnoreCase(dataType)) {
            // char -> String
            return ConstDataType.JAVA_STRING;
        }
        
        if (ConstDataType.MYSQL_INT.equalsIgnoreCase(dataType)) {
            // int -> int
            return ConstDataType.JAVA_INTEGER;
        }
        
        if (ConstDataType.MYSQL_DECIMAL.equalsIgnoreCase(dataType)) {
            
            // decimal(18,0) -> Long
            if (columnType.matches("decimal\\([ ]{0,}[\\d]{1,},[ ]{0,}0[ ]{0,}\\)")) {
                return ConstDataType.JAVA_LONG;
            }
            
            // decimal(18,2) -> Double
            return ConstDataType.JAVA_DOUBLE;
        }
        
        if (ConstDataType.MYSQL_BIGINT.equalsIgnoreCase(dataType)) {
            // bigint -> Long
            return ConstDataType.JAVA_LONG;
        }
        
        if (ConstDataType.MYSQL_DATETIME.equalsIgnoreCase(dataType)) {
            // datetime -> Date
            return ConstDataType.JAVA_DATE;
        }
        
        if (ConstDataType.MYSQL_DATE.equalsIgnoreCase(dataType)) {
            // date -> Date
            return ConstDataType.JAVA_DATE;
        }
        
        if (ConstDataType.MYSQL_SMALLINT.equalsIgnoreCase(dataType)) {
            // smallint -> Integer
            return ConstDataType.JAVA_INTEGER;
        }
        
        if (ConstDataType.MYSQL_TINYINT.equalsIgnoreCase(dataType)) {
            // tinyint -> Integer
            return ConstDataType.JAVA_INTEGER;
        }
        
        if (ConstDataType.MYSQL_DOUBLE.equalsIgnoreCase(dataType)) {
            // double -> Double
            return ConstDataType.JAVA_DOUBLE;
        }
        
        return ConstDataType.JAVA_STRING;
    }
    
}
